package com.cy.pj.web配置类和控制层.controller;

import com.cy.pj.common.pojo.JsonResult;
import com.cy.pj.common.pojo.SysUser;
import com.cy.pj.common.util工具类设计.PageUtil封装开启分页;
import com.cy.pj.service.SysUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user/")
public class SysUserController {
    @Autowired
    private SysUserService sysUserService;
//客户端修改密码业务
    @PatchMapping("password/{sourcePassword}/{newPassword}/{confirmPassword}")
    public JsonResult doUpdatePassword(@PathVariable String sourcePassword,
                                       @PathVariable String newPassword,
                                       @PathVariable String confirmPassword){
        sysUserService.updatePassword(sourcePassword,newPassword,confirmPassword);
        return new JsonResult("update ok");
    }

    @GetMapping("login/{username}/{password}")
    public JsonResult doLogin(@PathVariable String username,@PathVariable String password){
        //控制层方法拿到用户名和密码以后要将这个信息提交给谁?(给shiro)
        //通过谁提交?--官方规定:Subject
        //如何获取Subject?参考官方或源代码
        Subject subject= SecurityUtils.getSubject();
        //如何提交用户和密码?(官网规定:调用subject对象的login方法)
        /**1.为什么要创建个token类型的对象?
         *官网规定:页面的用户信息和密码都放到token类型的令牌里面，再用Subject的login方法
         * 传递给shiro框架
         */
        /**2.为什么要构建UsernamePasswordToken对象?--login方法的需要
         * 因为subject的login方法底层需要AuthenticationToken类型的对象,但它是接口类型，不能new创建实例，
         * 只能找它底层有哪些实现类,而UsernamePasswordToken就是它的一个实现类，可以new个实例化对象
         */
        UsernamePasswordToken token=new UsernamePasswordToken(username, password);
        token.setRememberMe(true);//设置--记住我
        subject.login(token);//提交给shiro的security Manager
        //获取登录以后的用户对象
        JsonResult jr=new JsonResult("登录ok");
        jr.setData(username);
        return jr;
    }

    /**
     * @Transactional 描述方法时，此方法为一个事务切入点方法
     * @RequiresPermissions 描述方法时，此方法为一个授权切入点方法，我们在
     * 访问此方法时就需要授权，有权限则可以访问，没有权限则抛出异常。那如何
     * 判定用户有没有访问此方法的权限呢？当我们在方法时，shiro框架底层会获取
     * 此方法上的 @RequiresPermissions注解，进而取到注解中的权限标识，然后
     * 会调用subject对象的checkPermissions(权限标识)方法检测用户是否有权限。
     *
     * 这个方法的权限检测调用流程分析？
     * subject->SecurityManager-Authorize-->Realm
     */
    @RequiresPermissions("sys:user:update")
    @PatchMapping("/{id}/{valid}")//@PatchMapping-应用于少量数据的更新
    public JsonResult doValidById(@PathVariable Integer id,@PathVariable Integer valid){
sysUserService.validById(id,valid);
return new JsonResult("update ok");
    }

    @PutMapping
    //控制层中，一个方法内不能写多个@RequestBody，不然会页面报错
    public JsonResult doUpdateUser(@RequestBody SysUser sysUser){
        sysUserService.updateUser(sysUser);
        return new JsonResult("update ok");
    }

    @PostMapping
    public JsonResult doSaveUser(@RequestBody SysUser sysUser){
        sysUserService.saveUser(sysUser);
        return new JsonResult("save ok");
    }

    @GetMapping("{id}")
    public JsonResult doFindById(@PathVariable Integer id){
return new JsonResult(sysUserService.findById(id));
    }

    /**注意:其他的方法没关系，但是把授权注解放在业务层的要分页查询的方法上时，执行操作结果会出错，结果会返回授权标识
     * 原因:执行顺序出了问题--底层会先执行Controller的分页查询，再执行业务层上的授权注解(底层操作，通过Realm拿到全部的注解标识)，
     * 而授权注解执行的优先大于方法执行的优先，这样会把全部的注解返回给分页查询的PageInfo，那页面结果就是显示授权标识了
     * 解决方法:把授权注解前移到Controller层，先执行授权注解，再执行分页查询，然后在服务端设置下请求url有效
     */
    @RequiresPermissions("sys:user:view")
    @GetMapping
public JsonResult doFindUsers(SysUser sysUser){
return new JsonResult(PageUtil封装开启分页.startPage().doSelectPageInfo(()->{
    sysUserService.findUsers(sysUser);
})); //结果交给谁?--DispatcherServlet



}
}
